﻿// Decompiled with JetBrains decompiler
// Type: DnProcessSimulateCommands.ToolPositioning.CApTPClassificationManager
// Assembly: DnProcessSimulateCommands, Version=2402.0.0.890, Culture=neutral, PublicKeyToken=null
// MVID: A885D881-AEDF-447E-852A-6F13102E089C
// Assembly location: C:\Program Files\Tecnomatix_2402\eMPower\DotNetCommands\DnProcessSimulateCommands.dll

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Tecnomatix.Engineering;


namespace DnProcessSimulateCommands.ToolPositioning;

internal class CApTPClassificationManager
{
  private static CApTPClassificationManager Instance = new CApTPClassificationManager();
  private DirectoryInfo _modelPath;
  private DirectoryInfo _contoursModelPath;
  private List<string> _categories = new List<string>()
  {
    "AllenKey",
    "BaseTool",
    "Fastener",
    "Nut",
    "Screwdriver",
    "Wrench"
  };
  private List<string> _contoursCategories = new List<string>()
  {
    "Slotted",
    "Cross",
    "Pozidriv",
    "Square",
    "Hex",
    "Torx"
  };
  private List<Tuple<IClassificationRequest, Task<Tuple<string, string>>, Action<object, string, string>>> _requests = new List<Tuple<IClassificationRequest, Task<Tuple<string, string>>, Action<object, string, string>>>();
  private bool _unloadRequested;

  private CApTPClassificationManager()
  {
    this._unloadRequested = false;
    this._modelPath = new DirectoryInfo(TxApplication.InstallationDirectory + "\\Model\\SmartTool");
    this._contoursModelPath = new DirectoryInfo(TxApplication.InstallationDirectory + "\\Model\\SmartToolContours");
  }

  private IList<Tuple<string, float>> ParseResults(string results, List<string> categories)
  {
    List<Tuple<string, float>> results1 = new List<Tuple<string, float>>();
    string[] source = results.Split(',');
    if (((IEnumerable<string>) source).Count<string>() == categories.Count)
    {
      int num = 0;
      foreach (string category in categories)
      {
        float result = 0.0f;
        if (!float.TryParse(source[num++].Trim(), NumberStyles.Float, (IFormatProvider) CultureInfo.InvariantCulture, out result))
          result = 0.0f;
        results1.Add(new Tuple<string, float>(category, result * 100f));
      }
    }
    return (IList<Tuple<string, float>>) results1;
  }

  private string PrintResults(IList<Tuple<string, float>> results)
  {
    return results != null && results.Count > 0 ? results.Aggregate<Tuple<string, float>, string>("", (Func<string, Tuple<string, float>, string>) ((result, current) => result + (result.Length > 0 ? ", " : "") + current.ToString())) : string.Empty;
  }

  private Tuple<string, float> GetMaxResult(IList<Tuple<string, float>> results)
  {
    return results != null && results.Count > 0 ? results.OrderByDescending<Tuple<string, float>, float>((Func<Tuple<string, float>, float>) (item => item.Item2)).First<Tuple<string, float>>() : (Tuple<string, float>) null;
  }

  private Tuple<string, string> ClassifyObjectInternal(ObjectClassificationRequest request)
  {
    string str1 = string.Empty;
    string str2 = string.Empty;
    if (request != null && request.PreviewImages != null)
    {
      IList<Tuple<string, float>> results = (IList<Tuple<string, float>>) new List<Tuple<string, float>>();
      foreach (string previewImage in request.PreviewImages)
      {
        IntPtr result;
        if (this._modelPath.Exists && CApTPClassificationManager.NttClassifyImage(this._modelPath.FullName, previewImage, out result))
        {
          string stringAnsi = Marshal.PtrToStringAnsi(result);
          results.Add(this.GetMaxResult(this.ParseResults(stringAnsi, this._categories)));
        }
      }
      List<Tuple<string, int>> list = results.GroupBy<Tuple<string, float>, string>((Func<Tuple<string, float>, string>) (x => x.Item1)).Select<IGrouping<string, Tuple<string, float>>, Tuple<string, int>>((Func<IGrouping<string, Tuple<string, float>>, Tuple<string, int>>) (sg => new Tuple<string, int>(sg.First<Tuple<string, float>>().Item1, (int) ((double) sg.Count<Tuple<string, float>>() / (double) results.Count * 100.0)))).OrderByDescending<Tuple<string, int>, int>((Func<Tuple<string, int>, int>) (x => x.Item2)).ToList<Tuple<string, int>>();
      str1 = "Cannot be classified!";
      str2 = "Unknown";
      if (list.Count <= 3)
      {
        str1 = list.Aggregate<Tuple<string, int>, string>("", (Func<string, Tuple<string, int>, string>) ((r, c) => $"{r}{(r.Length > 0 ? ", " : "")}{c.Item1}-{c.Item2.ToString()}%"));
        str2 = list.Aggregate<Tuple<string, int>, string>("", (Func<string, Tuple<string, int>, string>) ((r, c) => r + (r.Length > 0 ? ", " : "") + c.Item1));
      }
    }
    return new Tuple<string, string>(str1, str2);
  }

  private Tuple<string, string> ClassifyContourInternal(ContourClassificationRequest request)
  {
    string str1 = string.Empty;
    string str2 = string.Empty;
    if (request != null)
    {
      List<Tuple<string, float>> results = new List<Tuple<string, float>>();
      foreach (string contourPoint in request.ContourPoints)
      {
        IntPtr result;
        if (this._contoursModelPath.Exists && CApTPClassificationManager.NttClassifyContour(this._contoursModelPath.FullName, contourPoint, out result))
        {
          string stringAnsi = Marshal.PtrToStringAnsi(result);
          results.Add(this.GetMaxResult(this.ParseResults(stringAnsi, this._contoursCategories)));
        }
      }
      List<Tuple<string, int>> list = results.GroupBy<Tuple<string, float>, string>((Func<Tuple<string, float>, string>) (x => x.Item1)).Select<IGrouping<string, Tuple<string, float>>, Tuple<string, int>>((Func<IGrouping<string, Tuple<string, float>>, Tuple<string, int>>) (sg => new Tuple<string, int>(sg.First<Tuple<string, float>>().Item1, (int) ((double) sg.Count<Tuple<string, float>>() / (double) results.Count * 100.0)))).OrderByDescending<Tuple<string, int>, int>((Func<Tuple<string, int>, int>) (x => x.Item2)).ToList<Tuple<string, int>>();
      str1 = "Cannot be classified!";
      str2 = "Unknown";
      if (list.Count <= 3)
      {
        str1 = list.Aggregate<Tuple<string, int>, string>("", (Func<string, Tuple<string, int>, string>) ((r, c) => $"{r}{(r.Length > 0 ? ", " : "")}{c.Item1}-{c.Item2.ToString()}%"));
        str2 = list.Aggregate<Tuple<string, int>, string>("", (Func<string, Tuple<string, int>, string>) ((r, c) => r + (r.Length > 0 ? ", " : "") + c.Item1));
      }
    }
    return new Tuple<string, string>(str1, str2);
  }

  private void UnloadModelInternal()
  {
    CApTPClassificationManager.NttClassifyUnloadModel();
    CApTPClassificationManager.NttClassifyUnloadContourModel();
  }

  private void DeleteFile(string path)
  {
    try
    {
      if (!File.Exists(path))
        return;
      File.Delete(path);
    }
    catch
    {
    }
  }

  public static string ClassifyObject(ObjectClassificationRequest request)
  {
    return CApTPClassificationManager.Instance.ClassifyObjectInternal(request).Item2;
  }

  public static async void ClassifyObjectAsync(
    ObjectClassificationRequest request,
    Action<object, string, string> updateCallback)
  {
    CApTPClassificationManager.Instance._requests.Add(new Tuple<IClassificationRequest, Task<Tuple<string, string>>, Action<object, string, string>>((IClassificationRequest) request, new Task<Tuple<string, string>>((Func<Tuple<string, string>>) (() => request != null ? CApTPClassificationManager.Instance.ClassifyObjectInternal(request) : new Tuple<string, string>(string.Empty, string.Empty))), updateCallback));
    if (CApTPClassificationManager.Instance._requests.Count != 1)
      return;
    do
    {
      Tuple<IClassificationRequest, Task<Tuple<string, string>>, Action<object, string, string>> currentRequest = CApTPClassificationManager.Instance._requests[0];
      Task<Tuple<string, string>> task = currentRequest.Item2;
      if (!CApTPClassificationManager.Instance._unloadRequested)
      {
        task.Start();
        ITxObject requestObject = currentRequest.Item1.Object;
        currentRequest.Item3((object) requestObject, "Processing...", "");
        Tuple<string, string> tuple = await task;
        currentRequest.Item3((object) requestObject, task.Result.Item1, task.Result.Item2);
        requestObject = (ITxObject) null;
      }
      Task.Run((Action) (() =>
      {
        ObjectClassificationRequest classificationRequest = currentRequest.Item1 as ObjectClassificationRequest;
        if (classificationRequest.PreviewImages == null)
          return;
        classificationRequest.PreviewImages.ForEach((Action<string>) (x => CApTPClassificationManager.Instance.DeleteFile(x)));
      }));
      CApTPClassificationManager.Instance._requests.Remove(currentRequest);
      task = (Task<Tuple<string, string>>) null;
    }
    while (CApTPClassificationManager.Instance._requests.Count > 0);
  }

  public static string ClassifyContour(ContourClassificationRequest request)
  {
    return CApTPClassificationManager.Instance.ClassifyContourInternal(request).Item2;
  }

  public static void UnloadModel()
  {
    try
    {
      CApTPClassificationManager.Instance._unloadRequested = true;
      Task.Run((Action) (() =>
      {
        while (CApTPClassificationManager.Instance._requests.Count > 0)
          Task.Delay(500);
        CApTPClassificationManager.Instance._requests.Clear();
        CApTPClassificationManager.Instance.UnloadModelInternal();
      })).Wait(3000);
    }
    finally
    {
      CApTPClassificationManager.Instance._unloadRequested = false;
    }
  }

  public static bool AVXSupported() => CApTPClassificationManager.NttCPUAVXSupported();

  [DllImport("NTTools.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
  private static extern bool NttClassifyImage(
    string modelFile,
    string imageFile,
    out IntPtr result);

  [DllImport("NTTools.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
  private static extern void NttClassifyUnloadModel();

  [DllImport("NTTools.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
  private static extern bool NttClassifyContour(
    string modelFile,
    string contourPoints,
    out IntPtr result);

  [DllImport("NTTools.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
  private static extern void NttClassifyUnloadContourModel();

  [DllImport("NTTools.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
  private static extern bool NttCPUAVXSupported();
}
